package com.art.coconut.utils;

import com.art.coconut.change.BaseChangePojo;
import com.art.coconut.change.ChangePojo;
import com.art.coconut.change.PropertyProcessPojo;
import com.art.coconut.change.TypePojo;
import com.art.coconut.enums.ChangeTypeEnum;
import com.art.coconut.enums.PropertyTypeEnum;
import com.art.coconut.service.IPropertyProcess;

import java.util.*;

public class CoconutHelper {
    private final static Map<String, IPropertyProcess> typeProcessMap;
    static {
        typeProcessMap = new HashMap<>();
        for (PropertyTypeEnum processEnum : EnumSet.allOf(PropertyTypeEnum.class)) {
            typeProcessMap.put(processEnum.getTypeName(), processEnum.getPropertyProcess());
        }
    }

    public static void getChangeList(List<BaseChangePojo> objects, List<ChangePojo> changePojoList, ChangePojo parentPojo){
        for (ChangePojo pojo : changePojoList) {
            BaseChangePojo baseChangePojo = new BaseChangePojo();
            baseChangePojo.setBefore(pojo.getBefore());
            baseChangePojo.setAfter(pojo.getAfter());
            baseChangePojo.setTypeName(pojo.getTypeName());
            baseChangePojo.setTypeId(pojo.getTypeId());
            baseChangePojo.setChangeType(pojo.getChangeType());
            baseChangePojo.setEntityTag(pojo.getEntityTag());
            if(!Objects.isNull(parentPojo)){
                baseChangePojo.setParentId(parentPojo.getTypeId());
            }
            if(!Objects.isNull(pojo.getPropertyChangeList()) && !pojo.getPropertyChangeList().isEmpty()){
                baseChangePojo.setCollectionFlag(true);
            }
            if(!pojo.getCollectionFlag()){
                objects.add(baseChangePojo);
            }
            if(!Objects.isNull(pojo.getPropertyChangeList()) && !pojo.getPropertyChangeList().isEmpty()){
                getChangeList(objects, pojo.getPropertyChangeList(), pojo);
            }
        }
    }

    public static void processVersionMapAddAndRemove(List<ChangePojo> changeModelList
            , Map<Object, Object> oldVersionMap
            , Map<Object, Object> currVersionMap
            , ChangeTypeEnum changeTypeEnum
            , Class<?> itemClass
            , int depth) throws InstantiationException, IllegalAccessException {
        for (Object o : currVersionMap.keySet()) {
            if(!oldVersionMap.containsKey(o)){
                ChangePojo changePojo = new ChangePojo();
                changePojo.setTypeId(o.toString());
                changePojo.setTypeName(itemClass.getTypeName());
                changePojo.setChangeType(changeTypeEnum);
                changePojo.setEntityTag(ProcessHandle.getEntityTag(itemClass));
                if(ChangeTypeEnum.equals(changeTypeEnum, ChangeTypeEnum.ADDED)){
                    changePojo.setBefore(null);
                    changePojo.setAfter(currVersionMap.get(o));
                }else{
                    changePojo.setBefore(currVersionMap.get(o));
                    changePojo.setAfter(null);
                }
                List<ChangePojo> changeModels = new ArrayList<>();
                Map<String, TypePojo> currValueMap = ProcessHandle.objectToMap(currVersionMap.get(o), itemClass);
                for (Map.Entry<String, TypePojo> entry : currValueMap.entrySet()) {
                    if(Objects.isNull(entry.getValue().getObject())){
                        continue;
                    }
                    PropertyProcessPojo processPojo = new PropertyProcessPojo();
                    ChangePojo cp = new ChangePojo();
                    cp.setTypeName(entry.getKey());
                    cp.setTypeId(o.toString());
                    cp.setChangeType(changeTypeEnum);
                    if(ChangeTypeEnum.equals(changeTypeEnum, ChangeTypeEnum.ADDED)) {
                        cp.setBefore(null);
                        cp.setAfter(entry.getValue().getObject());
                        processPojo.setOld(null);
                        processPojo.setCurr(entry.getValue().getObject());
                    }else if(ChangeTypeEnum.equals(changeTypeEnum, ChangeTypeEnum.REMOVED)){
                        cp.setBefore(entry.getValue().getObject());
                        cp.setAfter(null);
                        processPojo.setOld(entry.getValue().getObject());
                        processPojo.setCurr(null);
                    }
                    cp.setEntityTag(entry.getValue().getEntityTag());

                    processPojo.setTypePojo(entry.getValue());
                    processPojo.setDepth(depth);
                    int addFlag = typeProcessMap.get(entry.getValue().getTypeName()).processObject(processPojo, cp);
                    changeModels.add(cp);
                }
                changePojo.setPropertyChangeList(changeModels);
                changeModelList.add(changePojo);
            }
        }
    }

    public static void processVersionMapModify(List<ChangePojo> changeModelList
            , Map<Object, Object> oldVersionMap
            , Map<Object, Object> currVersionMap
            , ChangeTypeEnum changeTypeEnum
            , Class<?> itemClass
            , int depth) throws InstantiationException, IllegalAccessException {
        for (Map.Entry<Object, Object> entry : oldVersionMap.entrySet()) {
            Object key = entry.getKey();
            if(currVersionMap.containsKey(key)){
                Object oldVersionMaValue = oldVersionMap.get(key);
                Object currVersionMaValue = currVersionMap.get(key);
                Map<String, TypePojo> oldValueMap = ProcessHandle.objectToMap(oldVersionMaValue, itemClass);
                Map<String, TypePojo> currValueMap = ProcessHandle.objectToMap(currVersionMaValue, itemClass);
                List<ChangePojo> propertyChangeModelList = new ArrayList<>();
                boolean isChanged = false;
                for (Map.Entry<String, TypePojo> oldEntry : oldValueMap.entrySet()) {
                    Object old = oldEntry.getValue().getObject();
                    Object curr = currValueMap.get(oldEntry.getKey()).getObject();
                    if(Objects.isNull(old) && Objects.isNull(curr)){
                        continue;
                    }
                    ChangePojo changePojo = new ChangePojo();
                    changePojo.setTypeId(key.toString());
                    changePojo.setTypeName(oldEntry.getKey());
                    changePojo.setBefore(old);
                    changePojo.setAfter(curr);
                    changePojo.setEntityTag(currValueMap.get(oldEntry.getKey()).getEntityTag());
                    PropertyProcessPojo processPojo = new PropertyProcessPojo();
                    processPojo.setTypePojo(oldEntry.getValue());
                    processPojo.setOld(old);
                    processPojo.setCurr(curr);
                    processPojo.setDepth(depth+1);
                    int addFlag = typeProcessMap.get(oldEntry.getValue().getTypeName()).processObject(processPojo, changePojo);
                    if(addFlag != 0){
                        changePojo.setChangeType(changeTypeEnum);
                        isChanged = true;
                    }else{
                        changePojo.setChangeType(ChangeTypeEnum.UNCHANGED);
                    }
                    propertyChangeModelList.add(changePojo);
                }
                ChangePojo changePojo = new ChangePojo();
                changePojo.setTypeName(itemClass.getTypeName());
                changePojo.setTypeId(key.toString());
                changePojo.setPropertyChangeList(propertyChangeModelList);
                changePojo.setBefore(entry.getValue());
                changePojo.setAfter(currVersionMap.get(entry.getKey()));
                changePojo.setEntityTag(ProcessHandle.getEntityTag(itemClass));
                if(isChanged){
                    changePojo.setChangeType(changeTypeEnum);
                }else{
                    changePojo.setChangeType(ChangeTypeEnum.UNCHANGED);
                }
                changeModelList.add(changePojo);
            }
        }
    }
}
